﻿using DataStructCenter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AlgorithmCenter
{
    /// <summary>
    /// 排队引擎
    /// </summary>
    public class QueueEngine
    {
        private static DoublyLinkedList<string> _queue = new DoublyLinkedList<string>();
        private static Dictionary<string, User> _userMaper = new Dictionary<string, User>();
        private static Dictionary<string, DoublyNode<string>> __userIdToNodeMap = new Dictionary<string, DoublyNode<string>>();
        private static int _userCount = 0;
        private static object _userIntoLock = new object();
        private static object _userOutLock = new object();

        #region 单例
        private readonly static QueueEngine queueEngine = new QueueEngine();
        private QueueEngine()
        {
        }
        public QueueEngine Instance
        {
            get {
                return queueEngine;
            }
        }
        #endregion


        /// <summary>
        /// 用户进入队列
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public Result UserIntoQueue(Guid userId)
        {
            lock (_userIntoLock)
            {
                if (_userMaper.ContainsKey(userId.ToString()))
                {
                    return new Result(200, "当前用户已在队列中");
                }

                //user into queue
                var node = _queue.AddToTail(userId.ToString());
                __userIdToNodeMap.Add(userId.ToString(), node);
                _userCount++;

                User user = new User();
                user.UserId = userId;
                user.QueueSerialNumber = _userCount;
                //user into map
                _userMaper.Add(userId.ToString(), user);
            }
            return Result.Success;
        }

        /// <summary>
        /// 用户出队列
        /// </summary>
        /// <param name="userId"></param>
        public void UserPopQueue(Guid userId)
        {
            var node = __userIdToNodeMap[userId.ToString()];
            var currentNodeNext = node.NextPoint;
            lock (_userOutLock)
            {
                _queue.DelNode(node);
                _userMaper.Remove(userId.ToString());
                __userIdToNodeMap.Remove(userId.ToString());
                _userCount--;
            }

            //触发广播事件
            Event.OnUserPopQue(currentNodeNext,_userMaper);
        }
    }

    public class User
    {
        public Guid UserId { get; set; }

        public int QueueSerialNumber { get; set; }
    }

    public static class Event
    {      
        public delegate void ChangeOtherUserSerialNumberDelegate(DoublyNode<string> node, Dictionary<string, User> userMaper);

        private static event ChangeOtherUserSerialNumberDelegate changeOtherUserSerialNumberEvent;

        static Event()
        {
            ChangeOtherUserSerialNumberEvent += ChangeOtherUserSerialNumber;
        }

        public static event ChangeOtherUserSerialNumberDelegate ChangeOtherUserSerialNumberEvent
        {
            add
            {
                changeOtherUserSerialNumberEvent += value;
            }
            remove
            {
                changeOtherUserSerialNumberEvent -= value;
            }
        }

        public static void OnUserPopQue(DoublyNode<string> node, Dictionary<string, User> userMaper)
        {
            changeOtherUserSerialNumberEvent(node,userMaper);
        }

        public static void ChangeOtherUserSerialNumber(DoublyNode<string> node, Dictionary<string, User> userMaper)
        {
            while (node != null)
            {
                var user = userMaper[node.Value];
                user.QueueSerialNumber++;
            }
        }
    }
}
